#include <jni.h>
#include <string>
#include <android/log.h>
#include <android/bitmap.h>
#include <math.h>
#include <malloc.h>



/**
 * 高斯模糊算法
 * @param pix 图像数据指针
 * @param w 图像宽
 * @param h 图像高
 * @param radius 模糊半径
 */
void gaussBlur(int *pix, int w, int h, int radius);

extern "C"
JNIEXPORT void JNICALL
Java_com_eden_c_Jni_gaussBlur(JNIEnv *env, jclass type, jobject bitmap, jint radius) {
    AndroidBitmapInfo info = {0};//初始化BitmapInfo结构体
    int *data = NULL;//初始化Bitmap图像数据指针
    AndroidBitmap_getInfo(env, bitmap, &info);//锁定Bitmap，并且获得指针,将信息传递到info
    AndroidBitmap_lockPixels(env, bitmap, (void **) &data);
    /**********高斯模糊算法作对int数组进行处理***********/
    //调用gaussBlur函数，把图像数据指针、图片长宽和模糊半径传入
    gaussBlur(data, info.width, info.height, radius);
    /****************************************************/
    AndroidBitmap_unlockPixels(env, bitmap);//解锁
}

void gaussBlur(int *pix, int w, int h, int radius) {
    float sigma = (float) (1.0 * radius / 2.57);
    float deno = (float) (1.0 / (sigma * sqrt(2.0 * M_PI)));
    float nume = (float) (-1.0 / (2.0 * sigma * sigma));
    float *gaussMatrix = (float *) malloc(sizeof(float) * (radius + radius + 1));
    float gaussSum = 0.0;
    for (int i = 0, x = -radius; x <= radius; ++x, ++i) {
        float g = (float) (deno * exp(1.0 * nume * x * x));
        gaussMatrix[i] = g;
        gaussSum += g;
    }
    int len = radius + radius + 1;
    for (int i = 0; i < len; ++i)
        gaussMatrix[i] /= gaussSum;
    int *rowData = (int *) malloc(w * sizeof(int));
    int *listData = (int *) malloc(h * sizeof(int));
    for (int y = 0; y < h; ++y) {
        memcpy(rowData, pix + y * w, sizeof(int) * w);
        for (int x = 0; x < w; ++x) {
            float r = 0, g = 0, b = 0;
            gaussSum = 0;
            for (int i = -radius; i <= radius; ++i) {
                int k = x + i;
                if (0 <= k && k <= w) {
                    //得到像素点的rgb值
                    int color = rowData[k];
                    int cr = (color & 0x00ff0000) >> 16;
                    int cg = (color & 0x0000ff00) >> 8;
                    int cb = (color & 0x000000ff);
                    r += cr * gaussMatrix[i + radius];
                    g += cg * gaussMatrix[i + radius];
                    b += cb * gaussMatrix[i + radius];
                    gaussSum += gaussMatrix[i + radius];
                }
            }
            int cr = (int) (r / gaussSum);
            int cg = (int) (g / gaussSum);
            int cb = (int) (b / gaussSum);
            pix[y * w + x] = cr << 16 | cg << 8 | cb | 0xff000000;
        }
    }
    for (int x = 0; x < w; ++x) {
        for (int y = 0; y < h; ++y)
            listData[y] = pix[y * w + x];
        for (int y = 0; y < h; ++y) {
            float r = 0, g = 0, b = 0;
            gaussSum = 0;
            for (int j = -radius; j <= radius; ++j) {
                int k = y + j;
                if (0 <= k && k <= h) {
                    int color = listData[k];
                    int cr = (color & 0x00ff0000) >> 16;
                    int cg = (color & 0x0000ff00) >> 8;
                    int cb = (color & 0x000000ff);
                    r += cr * gaussMatrix[j + radius];
                    g += cg * gaussMatrix[j + radius];
                    b += cb * gaussMatrix[j + radius];
                    gaussSum += gaussMatrix[j + radius];
                }
            }
            int cr = (int) (r / gaussSum);
            int cg = (int) (g / gaussSum);
            int cb = (int) (b / gaussSum);
            pix[y * w + x] = cr << 16 | cg << 8 | cb | 0xff000000;
        }
    }
    free(gaussMatrix);
    free(rowData);
    free(listData);
}


extern "C"
JNIEXPORT void JNICALL
Java_com_eden_c_Jni_test(JNIEnv *env, jclass type, jint a, jstring b_, jobject student) {
    const char *b = env->GetStringUTFChars(b_, 0);
    env->ReleaseStringUTFChars(b_, b);
    //
    jclass studentClass = env->GetObjectClass(student);
    jfieldID ageField = env->GetFieldID(studentClass, "age", "I");
    int age = env->GetIntField(student, ageField);
    //



}

//创建对象 并访问父类方法
extern "C"
JNIEXPORT jobject JNICALL
Java_com_eden_c_Jni_createObjectAndAccessSuperMethod(JNIEnv *env, jclass type) {
    //获取class引用
    jclass studentClass = env->FindClass("com/eden/c/Student");
    if (studentClass == NULL)return NULL;

    //获取构造方法id ,构造方法名称都是: <init>
    jmethodID stu_id = env->GetMethodID(studentClass, "<init>", "()V");
    if (stu_id == NULL)return NULL;
    //创建Student对象
    jobject student = env->NewObject(studentClass, stu_id);

    //调用子类没有重写的父类的方法1
    jclass personClass = env->FindClass("com/eden/c/Person");
    jmethodID method_1 = env->GetMethodID(personClass, "printInfo", "()V");
    env->CallVoidMethod(student, method_1);

    jmethodID m_id_2 = env->GetMethodID(personClass, "run", "()V");
    //调用子类重写了的父类方法
    env->CallNonvirtualVoidMethod(student, personClass, m_id_2);
    //调用子类的方法 子类重写了的父类方法
    env->CallVoidMethod(student, m_id_2);


    return student;
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_eden_c_Jni_accessStaticField(JNIEnv *env, jclass type, jobject student) {
    jclass clazz = env->GetObjectClass(student);
    jfieldID countId = env->GetStaticFieldID(clazz, "count", "I");
    jint countValue = env->GetStaticIntField(clazz, countId);

    __android_log_print(ANDROID_LOG_ERROR, "jni", "完成访问");
    return countValue;

}

//访问对象的成员变量
extern "C"
JNIEXPORT void JNICALL
Java_com_eden_c_Jni_accessInstanceField(JNIEnv *env, jclass type, jobject student) {
    //1.获取class对象
    jclass clazz = env->GetObjectClass(student);
    //2.获取属性id
    jfieldID nameId = env->GetFieldID(clazz, "name", "Ljava/lang/String;");
    //3.
    jstring nameValue = (jstring) env->GetObjectField(student, nameId);
    const char *s = env->GetStringUTFChars(nameValue, JNI_FALSE);
    __android_log_print(ANDROID_LOG_ERROR, "jni", "完成访问");
    __android_log_print(ANDROID_LOG_ERROR, "jni", s, "%s");

}

//访问静态方法
extern "C"
JNIEXPORT jstring JNICALL
Java_com_eden_c_Jni_accessStaticMethod(JNIEnv *env, jclass type, jint a) {
    //1.获取Student的class对象
    jclass clazz = env->FindClass("com/eden/c/Student");
    if (clazz == NULL)return env->NewStringUTF("");
    __android_log_print(ANDROID_LOG_ERROR, "jni", "第一步");
    //2.从class对象中查找方法 testGetString (I)Ljava/lang/String; 最后的分号必须跟上
    jmethodID jmethodID1 = env->GetStaticMethodID(clazz, "testGetString", "(I)Ljava/lang/String;");
    if (jmethodID1 == NULL)
        return env->NewStringUTF("");
    __android_log_print(ANDROID_LOG_ERROR, "jni", "第二步");
    //调用方法
    jstring result = (jstring) env->CallStaticObjectMethod(clazz, jmethodID1, a);
    //删除局部引用
    env->DeleteLocalRef(clazz);
    return result;
}

//访问对象的方法
extern "C"
JNIEXPORT jint JNICALL
Java_com_eden_c_Jni_accessInstanceMethod(JNIEnv *env, jclass type, jobject stu) {
//  __android_log_print(ANDROID_LOG_ERROR,"jni",env->callo)

    // 获取对象class
    jclass stuClass = env->GetObjectClass(stu);
    //获取方法id
    //第三个参数获取方法
    //1.打开命令行窗口进入到Student.java 所在目录
    //2.输入javac Student.java 得到Student.class
    //3.输入javap -s -p Student.class
    jmethodID method = env->GetMethodID(stuClass, "getScore", "()I");
    //调用方法
    jint score = env->CallIntMethod(stu, method);
    return score;

}




